#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
 
#include <openssl/err.h>
#include <openssl/dh.h>
#include <openssl/ssl.h>
#include <openssl/conf.h>
#include <openssl/engine.h>

#define CLIENT_PORT 5566
#define SERVER_PORT 4433
#define SERVER_IP "127.0.0.1"
#define MAX_PACKAGE_LEN (60 * 1024)

 
/* SSL debug */
#define SSL_WHERE_INFO(ssl, w, flag, msg) {                \
    if(w & flag) {                                         \
      printf("+ %s: ", name);                              \
      printf("%20.20s", msg);                              \
      printf(" - %30.30s ", SSL_state_string_long(ssl));   \
      printf(" - %5.10s ", SSL_state_string(ssl));         \
      printf("\n");                                        \
    }                                                      \
  } 
 
typedef void(*info_callback)(const SSL* ssl, int where, int ret);
 
typedef struct {
  SSL_CTX* ctx;                                                                       /* main ssl context */
  SSL* ssl;                                                                           /* the SSL* which represents a "connection" */
  BIO* in_bio;                                                                        /* we use memory read bios */
  BIO* out_bio;                                                                       /* we use memory write bios */
  char name[512];
} krx;
 
void krx_begin();                                                                     /* initialize SSL */
void krx_end();                                                                       /* shutdown SSL */
int krx_ssl_ctx_init(krx* k, const char* keyname);                                    /* initialize the SSL_CTX */
int krx_ssl_init(krx* k, int isserver, info_callback cb);                             /* init the SSL* (the "connection"). we use the `isserver` to tell SSL that it should either use the server or client protocol */
int krx_ssl_shutdown(krx* k);                                                         /* cleanup SSL allocated mem */
int krx_ssl_verify_peer(int ok, X509_STORE_CTX* ctx);                                 /* we set the SSL_VERIFY_PEER option on the SSL_CTX, so that the server will request the client certificate. We can use the certificate to get/verify the fingerprint */
int krx_ssl_handle_traffic(krx* from, krx* to);
int krx_ssl_handle_traffic_read(krx* from, char* outbuf, int& read);
int krx_ssl_handle_traffic_write(char* outbuf, const int& read, krx* to);
 
/* some debug info */
void krx_ssl_server_info_callback(const SSL* ssl, int where, int ret);                /* purely for debug purposes; logs server info. */
void krx_ssl_client_info_callback(const SSL* ssl, int where, int ret);                /* client info callback */
void krx_ssl_info_callback(const SSL* ssl, int where, int ret, const char* name);     /* generic info callback */

int ProcessOnDtls(char* buf, int buflen, krx *k, char* replybuf, int& replylen);
int CreateSocket(short port);
void print_dump(unsigned char* buff, int buff_len);
